unit uUndoManager ;

interface

uses
   SysUtils,
   Classes,
   Contnrs,
   uBasic,
   ActnList, ImgList, Controls, PngImageList ;

type

   TdmUndoManager = class( TDataModule )
      ActionList : TActionList ;
      actUndo : TAction ;
      actRedo : TAction ;
    PngImageList: TPngImageList;
    actCut: TAction;
    actCopy: TAction;
    actPaste: TAction;
      procedure actUndoExecute( Sender : TObject ) ;
      procedure actUndoUpdate( Sender : TObject ) ;
      procedure actRedoExecute( Sender : TObject ) ;
      procedure actRedoUpdate( Sender : TObject ) ;
      procedure DataModuleCreate( Sender : TObject ) ;
      procedure DataModuleDestroy( Sender : TObject ) ;
   private
      { Private declarations }
      fUndoStack : TStack ;
      fRedoStack : TStack ;
   public
      { Public declarations }
      procedure Clear ;
      procedure Add( aMemento : TMemento ) ;
      function CanUndo : boolean ;
      procedure Undo ;
      function CanRedo : boolean ;
      procedure Redo ;
   end ;

var
   dmUndoManager    : TdmUndoManager ;

implementation

{$R *.dfm}

uses
   uMain ;

{ TdmUndoManager }

procedure TdmUndoManager.Add( aMemento : TMemento ) ;
begin
   fUndoStack.Push( aMemento ) ;
   with fRedoStack do                   // Clear ;
      while Count > 0 do
         Pop ;
end ;

procedure TdmUndoManager.Clear ;
begin
   with fUndoStack do                   // Clear ;
      while Count > 0 do
         Pop ;
   with fRedoStack do                   // Clear ;
      while Count > 0 do
         Pop ;
end ;

function TdmUndoManager.CanRedo : boolean ;
begin
   Result := fRedoStack.Count > 0 ;
end ;

procedure TdmUndoManager.Redo ;
var
   iMemento          : TMemento ;
begin
   iMemento := fUndoStack.Pop ;
   iMemento.Undo ;
   fRedoStack.Push( iMemento ) ;
end ;

function TdmUndoManager.CanUndo : boolean ;
begin
   Result := fUndoStack.Count > 0 ;
end ;

procedure TdmUndoManager.Undo ;
var
   iMemento          : TMemento ;
begin
   iMemento := fRedoStack.Pop ;
   iMemento.Redo ;
   fUndoStack.Push( iMemento ) ;
end ;

procedure TdmUndoManager.actUndoExecute( Sender : TObject ) ;
begin
   Undo ;
end ;

procedure TdmUndoManager.actUndoUpdate( Sender : TObject ) ;
begin
   ( sender as TAction ).Enabled := CanUndo ;
end ;

procedure TdmUndoManager.actRedoExecute( Sender : TObject ) ;
begin
   Redo ;
end ;

procedure TdmUndoManager.actRedoUpdate( Sender : TObject ) ;
begin
   ( sender as TAction ).Enabled := CanRedo ;
end ;

procedure TdmUndoManager.DataModuleCreate( Sender : TObject ) ;
begin
   fUndoStack := TStack.Create ;
   fRedoStack := TStack.Create ;
end ;

procedure TdmUndoManager.DataModuleDestroy( Sender : TObject ) ;
begin
   fRedoStack.Free ;
   fUndoStack.Free ;
end ;

initialization
   dmUndoManager := TdmUndoManager.Create( nil ) ;

finalization
   dmUndoManager.Free ;

end.

 